#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/signalfd.h>
#include <unistd.h>
#include <signal.h>
#include <errno.h>

typedef struct {
    int argc;
    void* argv;
    void (*job_func)(int, void*);
} Job;

static void do_job(int argc, void* argv)
{
    int i = 5;
    printf("do_job: %d --> %s...\n", argc, (char*)argv);
    while (i-- > 0) {
        sleep(1);
    }
}
static Job g_job[] = {
    {1, "Delphi", do_job},
    {2, "D.T.Software", do_job},
    {3, "Tang", do_job},
};

static const int g_jlen = sizeof(g_job) / sizeof(*g_job);
static siginfo_t g_sig_arr[65] = {0};
static const int g_slen = sizeof(g_sig_arr) / sizeof(*g_sig_arr);
static int g_sig_fd = -1;

static int mask_all_signal()
{
    sigset_t set = {0};
    sigfillset(&set);
    sigprocmask(SIG_SETMASK, &set, NULL);

    return signalfd(-1, &set, 0);
}

static void do_sig_process(struct signalfd_siginfo* info)
{
    printf("do_sig_process: %d --> %d\n", info->ssi_signo, info->ssi_int);
    // do process for the obj signal
    switch (info->ssi_signo) {
        case SIGINT:
            // call process function for SIGINT
            break;
        case 40:
            // call process function for 40
            break;
        default:
            break;
    }
}

static int select_handler(fd_set* rset, fd_set* reads, int max)
{
    int ret = max;
    int i = 0;
    for (i = 0; i <= max; i++) {
        if (FD_ISSET(i, rset)) {
            if (i == g_sig_fd) {
                struct signalfd_siginfo si = {0};

                if (read(g_sig_fd, &si, sizeof(si)) > 0) {
                    do_sig_process(&si);
                }
            } else {
                // handler other fd
                // the return value should be the max fd value
                // max = (max < fd) ? fd : max
            }

            FD_CLR(i, reads);
            ret = max;
        }
    }
}

static void process_signal()
{
    static int max = 0;

    fd_set reads = {0};
    fd_set rset = {0};
    struct timeval timeout = {0};

    FD_ZERO(&reads);
    FD_SET(g_sig_fd, &reads);

    max = g_sig_fd;
    rset = reads;

    timeout.tv_sec = 0;
    timeout.tv_usec = 5000;

    while (select(max + 1, &rset, 0, 0, &timeout) > 0) {
        max = select_handler(&rset, &reads, max);
    }
}

static void app_init()
{
    struct sigaction act = {0};
    sigset_t set = {0};
    int i = 0;
    act.sa_flags = SA_RESTART | SA_SIGINFO;
    for (i = 1; i <= 64; i++) {
        sigaddset(&act.sa_mask, i);
    }
    for (i = 1; i <= 64; i++) {
        sigaction(i, &act, NULL);
    }

    g_sig_fd = mask_all_signal();
}

int main(int argc, char* argv[])
{
    int i = 0;
    printf("current pid(%d) ...\n", getpid());
    app_init();

    while (i < g_jlen) {
        int argc = g_job[i].argc;
        char* argv = g_job[i].argv;

        g_job[i].job_func(argc, argv);
        
        process_signal();

        i++;
    }

    return 0;
}
